package com.jingxuan.service.impl;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.time.Duration;
import java.time.LocalDateTime;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.util.ReflectionTestUtils;

import com.jingxuan.mapper.ProductsMapper;
import com.jingxuan.mapper.RecommendMapper;
import com.jingxuan.util.UserBehaviorAlgorithm.BrowseRecord;

/**
 * Tests for {@link UserBehaviorServiceImpl}.
 */
class UserBehaviorServiceImplTest {

    private UserBehaviorServiceImpl service;
    private RedisTemplate<String, Object> redisTemplate;
    private ProductsMapper productsMapper;
    private RecommendMapper recommendMapper;
    private ValueOperations<String, Object> valueOperations;
    private SetOperations<String, Object> setOperations;
    @SuppressWarnings("unchecked")
    private HashOperations<String, Object, Object> hashOperations;

    @BeforeEach
    void setUp() {
        redisTemplate = Mockito.mock(RedisTemplate.class);
        productsMapper = Mockito.mock(ProductsMapper.class);
        recommendMapper = Mockito.mock(RecommendMapper.class);
        valueOperations = Mockito.mock(ValueOperations.class);
        setOperations = Mockito.mock(SetOperations.class);
        hashOperations = Mockito.mock(HashOperations.class);

        service = new UserBehaviorServiceImpl(recommendMapper);
        ReflectionTestUtils.setField(service, "redisTemplate", redisTemplate);
        ReflectionTestUtils.setField(service, "productsMapper", productsMapper);

        when(redisTemplate.opsForValue()).thenReturn(valueOperations);
        when(valueOperations.get(anyString())).thenReturn(null);

        when(redisTemplate.opsForSet()).thenReturn(setOperations);
        when(setOperations.add(anyString(), Mockito.<Object>any())).thenReturn(1L);

        when(redisTemplate.opsForHash()).thenReturn(hashOperations);
        when(hashOperations.increment(anyString(), any(), anyLong())).thenReturn(1L);

        when(recommendMapper.getProductFeaturesByIds(any())).thenReturn(java.util.Collections.emptyList());
        when(productsMapper.selectById(any())).thenReturn(null);
    }

    @Test
    void recordBrowseBehavior_shouldPersistForShortAndShallowPayloads() {
        BrowseRecord record = BrowseRecord.builder()
            .userId(123L)
            .productId("SKU-1")
            .startTime(LocalDateTime.now().minusSeconds(2))
            .endTime(LocalDateTime.now())
            .pageDepth(1)
            .pageCount(1)
            .build();

        service.recordBrowseBehavior(record);

        verify(valueOperations, times(1)).set(eq("behavior:user:123"), any());
        assertThat(record.getPageDepth()).isGreaterThanOrEqualTo(2);
        assertThat(Duration.between(record.getStartTime(), record.getEndTime()).toSeconds())
            .isGreaterThanOrEqualTo(3);
    }
}
